#include "AST.h"
#include <sstream>

namespace MiniDB
{

    std::string SelectStatement::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "SelectStatement:\n";
        ss << prefix << "  Select List:\n";
        for (const auto &expr : select_list)
        {
            ss << expr->toString(indent + 4);
        }
        ss << from_clause->toString(indent + 1);
        if (where_clause)
        {
            ss << prefix << "  Where:\n"
               << where_clause->toString(indent + 4);
        }
        return ss.str();
    }

    std::string InsertStatement::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "InsertStatement:\n";
        ss << prefix << "  Table: " << table_name << "\n";
        if (!columns.empty())
        {
            ss << prefix << "  Columns: ";
            for (size_t i = 0; i < columns.size(); ++i)
            {
                ss << columns[i];
                if (i < columns.size() - 1)
                    ss << ", ";
            }
            ss << "\n";
        }
        ss << prefix << "  Values:\n";
        for (const auto &row : values)
        {
            ss << prefix << "    Row:\n";
            for (const auto &expr : row)
            {
                ss << expr->toString(indent + 6);
            }
        }
        return ss.str();
    }

    std::string UpdateStatement::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "UpdateStatement:\n";
        ss << prefix << "  Table: " << table_name << "\n";
        ss << prefix << "  Assignments:\n";
        for (const auto &assignment : assignments)
        {
            ss << prefix << "    " << assignment.first << " = "
               << assignment.second->toString(0);
        }
        if (where_clause)
        {
            ss << prefix << "  Where:\n"
               << where_clause->toString(indent + 4);
        }
        return ss.str();
    }

    std::string DeleteStatement::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "DeleteStatement:\n";
        ss << prefix << "  Table: " << table_name << "\n";
        if (where_clause)
        {
            ss << prefix << "  Where:\n"
               << where_clause->toString(indent + 4);
        }
        return ss.str();
    }

    std::string CreateTableStatement::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "CreateTable: " << table_name << "\n";
        for (const auto &col : columns)
        {
            ss << col->toString(indent + 1);
        }
        return ss.str();
    }

    std::string DropTableStatement::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "DropTable: " << table_name << "\n";
        return ss.str();
    }

    std::string FromClause::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "From: " << table_name << "\n";
        if (!alias.empty())
        {
            ss << prefix << "  Alias: " << alias << "\n";
        }
        return ss.str();
    }

    std::string ColumnDefinition::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "Column: " << column_name << " " << data_type;
        if (!constraints.empty())
        {
            ss << " (";
            for (size_t i = 0; i < constraints.size(); ++i)
            {
                ss << constraints[i];
                if (i < constraints.size() - 1)
                    ss << ", ";
            }
            ss << ")";
        }
        ss << "\n";
        return ss.str();
    }

    std::string BinaryExpression::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "BinaryExpression (" << operator_ << "):\n";
        ss << left->toString(indent + 1);
        ss << right->toString(indent + 1);
        return ss.str();
    }

    std::string UnaryExpression::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "UnaryExpression (" << operator_ << "):\n";
        ss << operand->toString(indent + 1);
        return ss.str();
    }

    std::string ColumnReference::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "Column: " << column_name;
        if (!table_name.empty())
        {
            ss << " (" << table_name << ")";
        }
        ss << "\n";
        return ss.str();
    }

    std::string Literal::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "Literal: ";
        if (std::holds_alternative<std::string>(value))
        {
            ss << "'" << std::get<std::string>(value) << "'";
        }
        else if (std::holds_alternative<int>(value))
        {
            ss << std::get<int>(value);
        }
        else if (std::holds_alternative<double>(value))
        {
            ss << std::get<double>(value);
        }
        ss << " (" << value_type << ")\n";
        return ss.str();
    }

    std::string FunctionCall::toString(int indent) const
    {
        std::string prefix(indent, ' ');
        std::stringstream ss;
        ss << prefix << "FunctionCall: " << function_name << "(";
        for (size_t i = 0; i < arguments.size(); ++i)
        {
            ss << arguments[i]->toString(0);
            if (i < arguments.size() - 1)
                ss << ", ";
        }
        ss << ")\n";
        return ss.str();
    }

} // namespace MiniDB
